package com.dingreading.cloud.web.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.aliyun.CdnUtil;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.common.util.wechat.AuthToken;
import com.dingreading.cloud.common.util.wechat.WxPayBusiness;
import com.dingreading.cloud.web.entity.TellHistoryCode;
import com.dingreading.cloud.web.entity.TellHistoryLog;
import com.dingreading.cloud.web.entity.TellHistoryVideo;
import com.dingreading.cloud.web.service.TellHistoryCodeService;
import com.dingreading.cloud.web.service.TellHistoryLogService;
import com.dingreading.cloud.web.service.TellHistoryVideoService;
import com.dingreading.cloud.web.util.redis.RedisService;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@RefreshScope
@RestController
@RequestMapping(value = "/front/tellHistory")
@Api(tags = "前端-梧桐去讲历史")
public class FrontTellHistoryController {

    // 叮叮文化
    @Value("${wx.appId}")
    private String appId;
    @Value("${wx.appSecret}")
    private String appSecret;

    /**
     * cdn加速域名
     */
    @Value("${aliYun.cdn.ossDomain}")
    private String cdnOssDomain;

    @Resource
    protected TellHistoryVideoService tellHistoryVideoService;
    @Resource
    protected TellHistoryCodeService tellHistoryCodeService;
    @Resource
    protected TellHistoryLogService tellHistoryLogService;
    @Resource
    protected RedisService redisService;


    @ApiOperation(value = "微信获取openid接口(合肥叮叮文化科技有限公司)")
    @PostMapping(value = "/getOpenId", produces = "application/json; charset=UTF-8")
    public R<Object> getOpenId(
            @ApiParam(value = "微信授权码") @RequestParam(value = "code") String code
    ) throws Exception {
        String redisKey = "authAccess_" + code;
        String redisAccessToken = (String) redisService.get(redisKey);

        AuthToken authToken = null;
        if (StringUtils.isNotEmpty(redisAccessToken)) {
            authToken = JSONObject.parseObject(redisAccessToken, AuthToken.class);
        } else {
            authToken = WxPayBusiness.Init().getAccessToken(code, appId, appSecret);

            // 缓存code获取的accessToken
            redisService.set(redisKey, JSONObject.toJSONString(authToken), 7200);
        }
        if (authToken != null) {
            if (authToken.getErrcode() == null)
                return R.ok(authToken.getOpenid());
            else
                return R.fail(authToken.getErrmsg());
        } else {
            return R.fail("获取微信openid失败");
        }
    }

    @ApiOperation(value = "openid绑定授权码")
    @PostMapping(value = "/openidBindCode", produces = "application/json; charset=UTF-8")
    public R<Object> openidBindCode(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid,
            @ApiParam(value = "授权码") @RequestParam(value = "code") String code,
            @ApiParam(value = "图片验证码") @RequestParam(value = "picCode") String picCode,
            @ApiParam(value = "时间戳") @RequestParam(value = "timestamp") String timestamp
    ) throws Exception {
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户id不存在");
        if (StringUtils.isBlank(code) || code.length() != 8)
            return R.fail("请填写正确的授权码");
        if (StringUtils.isBlank(timestamp))
            return R.fail("未传递时间戳");
        if (StringUtils.isBlank(picCode) || picCode.length() != 4)
            return R.fail("请填写正确的验证码");

        // 验证验证码
        String redisPicCode = redisService.getValue("pic_code_" + timestamp);
        if (StringUtils.isNotBlank(redisPicCode)) {
            String upperCode = picCode.toUpperCase();
            if (!redisPicCode.equals(upperCode)) {
                return R.fail("验证码错误");
            }
        } else {
            return R.fail("验证码已失效");
        }

        long haveBind = tellHistoryCodeService.getByOpenidAndCode(openid);
        if (haveBind > 0)
            return R.fail("您已绑定授权码，不能重复绑定");

        TellHistoryCode data = tellHistoryCodeService.getByCode(code);
        if (data == null)
            return R.fail("未查询到授权码");
        if (StringUtils.isNotBlank(data.getOpenid()))
            return R.fail("授权码已被绑定，请更换授权码");

        data.setOpenid(openid);
        data.setBindTime(DateUtil.getNowDatetime());
        tellHistoryCodeService.saveOrUpdate(data);

        return R.ok();
    }

    @ApiOperation(value = "openid是否绑定授权码")
    @PostMapping(value = "/judgeBind", produces = "application/json; charset=UTF-8")
    public R<Object> judgeBind(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid
    ) throws Exception {
        TellHistoryCode data = tellHistoryCodeService.getByOpenid(openid);
        if (data != null)
            return R.ok(1);

        return R.ok(0);
    }

    @ApiOperation(value = "视频列表")
    @PostMapping(value = "/videoList", produces = "application/json; charset=UTF-8")
    public R<Object> videoList(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid
    ) {
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户id不存在");

        TellHistoryCode data = tellHistoryCodeService.getByOpenid(openid);
        if (data == null)
            return R.fail("未被授权，请先去绑定授权码");

        List<TellHistoryVideo> list = tellHistoryVideoService.getList(1);

        return R.ok(list);
    }

    @ApiOperation(value = "获取视频观看地址")
    @PostMapping(value = "/getBean")
    public R<Object> getBean(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid,
            @ApiParam(value = "视频id") @RequestParam(value = "id") Long id
    ) throws Exception {
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户id不存在");

        TellHistoryCode data = tellHistoryCodeService.getByOpenid(openid);
        if (data == null)
            return R.fail("未被授权，请先去绑定授权码");

        TellHistoryVideo video = tellHistoryVideoService.getById(id);
        if (video == null)
            return R.fail("视频获取失败");

        // 创建浏览记录
        TellHistoryLog log = new TellHistoryLog();
        log.setOpenid(openid);
        log.setVideoId(id);
        log.setTime(0);
        tellHistoryLogService.saveOrUpdate(log);

        String videoUrl = video.getUrl();

        // 阿里云cdn的url鉴权，源站是阿里云OSS
        String urlAuthA = CdnUtil.getUrlAuthA("/" + videoUrl);
        String authUrl = cdnOssDomain + videoUrl + urlAuthA;

        JSONObject jsonObject = JsonUtil.toJsonObject(video);
        jsonObject.put("videoUrl", authUrl);

        return R.ok(jsonObject);
    }

    @ApiOperation(value = "获取最后一次的视频浏览记录")
    @PostMapping(value = "/getLastVideLog")
    public R<Object> getLastVideLog(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid
    ) throws Exception {
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户id不存在");

        TellHistoryLog log = tellHistoryLogService.getLastVideLog(openid);

        return R.ok(log);
    }

    @ApiOperation(value = "添加视频浏览记录")
    @PostMapping(value = "/newVideoLog")
    public R<Object> newVideoLog(
            @ApiParam(value = "微信openid") @RequestParam(value = "openid") String openid,
            @ApiParam(value = "视频id") @RequestParam(value = "id") Long id,
            @ApiParam(value = "观看时长/秒") @RequestParam(value = "time") Integer time
    ) throws Exception {
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户id不存在");

        // 创建浏览记录
        TellHistoryLog log = new TellHistoryLog();
        log.setOpenid(openid);
        log.setVideoId(id);
        log.setTime(time);
        tellHistoryLogService.saveOrUpdate(log);

        return R.ok();
    }

    @ApiOperation(value = "获取图片验证码")
    @GetMapping(value = "/getPicCode", produces = "application/json; charset=UTF-8")
    public void getPicCode(
            HttpServletResponse response,
            @ApiParam(value = "时间戳") @RequestParam(value = "timestamp") String timestamp
    ) throws Exception {
        // 设置响应的类型格式为图片格式
        response.setContentType("image/jpeg");
        // 禁止图像缓存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        //实例生成验证码对象
        SCaptcha instance = new SCaptcha();
        String code = instance.getCode();
        if (StringUtils.isNotBlank(code)) {
            //将验证码存入redis
            redisService.set("pic_code_" + timestamp, code, 120);
            //向页面输出验证码图片
            instance.write(response.getOutputStream());
        }
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "批量生成授权码")
    @PostMapping(value = "/batchSave", produces = "application/json; charset=UTF-8")
    public void batchSave(
            HttpServletResponse response,
            @ApiParam(value = "生成数量") @RequestParam(value = "num") Integer num,
            @ApiParam(value = "渠道名称") @RequestParam(value = "channelName") String channelName
    ) throws Exception {
        if (num == null || num <= 0)
            throw new DescribeException("请填写正确的数量");
        if (num > 500)
            throw new DescribeException("数量不能大于500");

        Set<String> codeList = new HashSet<>();
        for (int i = 0; i < num; i++) {
            String upperRandomStr = KitUtil.getUpperRandomStr(8);

            codeList.add(upperRandomStr);
        }

        List<String> codes = tellHistoryCodeService.getByCodes(Lists.newArrayList(codeList));
        // 删除和已保存的相同数据
        if (CollectionUtils.isNotEmpty(codes))
            codes.forEach(codeList::remove);

        List<TellHistoryCode> newList = new ArrayList<>();
        List<List<String>> voList = new ArrayList<>();
        for (String code : codeList) {
            TellHistoryCode data = new TellHistoryCode();
            data.setCode(code);
            data.setChannelName(channelName);
            newList.add(data);

            List<String> data0 = new ArrayList<>();
            data0.add(code);
            voList.add(data0);
        }
        tellHistoryCodeService.saveOrUpdateBatch(newList);

        // 导出授权码
        String fileName = "授权码-" + channelName;
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                // 这里放入动态头
                .head(head()).sheet("授权码")
                // 当然这里数据也可以用 List<List<String>> 去传入
                .doWrite(voList);
    }

    /**
     * 表格的动态头
     */
    private List<List<String>> head() {
        List<List<String>> list = new ArrayList<>();
        List<String> head0 = new ArrayList<>();
        head0.add("授权码");
        list.add(head0);
        return list;
    }

}
